﻿using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.SceneGraph.Transformations;

namespace SharpGL.SceneGraph.Effects
{
    /// <summary>
    /// A Linear Transformation is an effect that pushes a linear transformation (translate, scale, rotate)
    /// onto the stack.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "LinearTransformationEffect", Namespace = "SharpGL.SceneGraph")]
    public class LinearTransformationEffect : Effect
    {
        #region Private Consts

        private static readonly string defaultName = "Liner transrotmation effect";

        #endregion Private Consts

        #region Private Fields

        /// <summary>
        /// The linear transformation.
        /// </summary>
        [DataMember()]
        private LinearTransformation linearTransformation = new LinearTransformation();

        #endregion Private Fields

        #region Private Methods

        private void OnLinearTransformationPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChanged(sender.GetType() + "." + e.PropertyName);
        }

        #endregion Private Methods

        #region Protected Methods

        protected override void OnDeserialized()
        {
            linearTransformation.PropertyChanged += new PropertyChangedEventHandler(OnLinearTransformationPropertyChanged);
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="LinearTransformationEffect"/> class.
        /// </summary>
        public LinearTransformationEffect()
        {
            Name = defaultName;
            linearTransformation.PropertyChanged += new PropertyChangedEventHandler(OnLinearTransformationPropertyChanged);
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Pushes the effect onto the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Push(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                // Push the stack.
                gl.PushMatrix();

                // Perform the transformation.
                linearTransformation.Transform(gl);
            }
        }

        /// <summary>
        /// Pops the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Pop(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                // Pop the stack.
                gl.PopMatrix();
            }
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the linear transformation.
        /// </summary>
        /// <value>
        /// The linear transformation.
        /// </value>
        [Description("The linear transformation."), Category("Effect")]
        public LinearTransformation LinearTransformation
        {
            get { return linearTransformation; }
            set
            {
                if (linearTransformation != value)
                {
                    linearTransformation.PropertyChanged -= new PropertyChangedEventHandler(OnLinearTransformationPropertyChanged);
                        
                    if (value == null)
                        linearTransformation = new LinearTransformation();
                    else
                        linearTransformation = value;

                    linearTransformation.PropertyChanged += new PropertyChangedEventHandler(OnLinearTransformationPropertyChanged);

                    NotifyPropertyChanged("LinearTransformation");
                }
            }
        }

        #endregion Public Properties
    }
}
